﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using Wf5.Engine.Common;

using FCDB.Entity;
using FCDB.Repository;

namespace Wf5.Engine.Business
{
    /// <summary>
    /// 节点转移管理类
    /// </summary>
    internal class TransitionInstanceManager
    {
        #region TransitionInstanceManager 属性和构造函数
        private WfTransitionInstanceRepository _transitionInstanceRepository;
        private WfTransitionInstanceRepository TransitionInstanceRepository
        {
            get
            {
                if (_transitionInstanceRepository == null)
                {
                    _transitionInstanceRepository = new WfTransitionInstanceRepository();
                }
                return _transitionInstanceRepository;
            }
        }
        #endregion

        internal WfTransitionInstance CreateTransitionInstanceObject(WfProcessInstance processInstance,
            Guid transitionGUID,
            WfActivityInstance fromActivityInstance,
            WfActivityInstance toActivityInstance,
            TransitionTypeEnum transitionType,
            TransitionFlyingTypeEnum flyingType,
            WfLogonUser logonUser,
            byte conditionParseResult)
        {
            var entity = new WfTransitionInstance();
            entity.ID = IDCreateLogic.GenerateID("WfTransition", "流程流转ID");
            entity.AppName = processInstance.AppName;
            entity.AppInstanceID = processInstance.AppInstanceID;
            entity.ProcessGUID = processInstance.ProcessGUID;
            entity.ProcessInstanceID = processInstance.ID;
            entity.TransitionGUID = transitionGUID;
            entity.TransitionType = (byte)transitionType;
            entity.FlyingType = (byte)flyingType;

            //构造活动节点数据
            entity.FromActivityGUID = fromActivityInstance.ActivityGUID;
            entity.FromActivityInstanceID = fromActivityInstance.ID;
            entity.FromActivityType = fromActivityInstance.ActivityType;
            entity.FromActivityName = fromActivityInstance.ActivityName;
            entity.ToActivityGUID = toActivityInstance.ActivityGUID;
            entity.ToActivityInstanceID = toActivityInstance.ID;
            entity.ToActivityType = toActivityInstance.ActivityType;
            entity.ToActivityName = toActivityInstance.ActivityName;

            entity.ConditionParseResult = conditionParseResult;
            entity.CreatedByUserID = logonUser.UserID;
            entity.CreatedByUserName = logonUser.UserName;
            entity.CreatedDateTime = System.DateTime.Now;

            return entity;
        }

        #region 数据增删改查
        internal WfTransitionInstance GetById(int transitionInstanceID)
        {
            return TransitionInstanceRepository.Get<WfTransitionInstance>(transitionInstanceID);
        }

        internal WfTransitionInstance GetEndTransition(string appName, long appInstanceID, Guid processGUID)
        {
            var nodeList = GetTransitonInstance(appName, appInstanceID, processGUID, NodeTypeEnum.EndNode).ToList();

            if (nodeList == null || nodeList.Count == 0)
            {
                throw new WorkflowException("没有流程结束的流转记录！");
            }

            return nodeList[0];
        }

        internal WfTransitionInstance GetLastTaskTransition(string appName, long appInstanceID, Guid processGUID)
        {
            var nodeList = GetTransitonInstance(appName, appInstanceID, processGUID, NodeTypeEnum.TaskNode).ToList();

            if (nodeList.Count == 0)
            {
                throw new WorkflowException("没有符合条件的最后流转任务的实例数据，请查看流程其它信息！");
            }

            return nodeList[0];
        }

        /// <summary>
        /// 根据去向节点类型选择转移数据
        /// </summary>
        /// <param name="appName"></param>
        /// <param name="appInstanceID"></param>
        /// <param name="processGUID"></param>
        /// <param name="toActivityType"></param>
        /// <returns></returns>
        internal IEnumerable<WfTransitionInstance> GetTransitonInstance(string appName, long appInstanceID, Guid processGUID, 
            NodeTypeEnum toActivityType)
        { 
            IList<WfTransitionInstance> transitionList = TransitionInstanceRepository.GetTransitonInstance(appName, appInstanceID, processGUID, (short)toActivityType); 

            return transitionList;
        }

        internal IEnumerable<WfTransitionInstance> GetTransitionInstanceList(long appInstanceID,
            Guid processGUID,
            long processInstanceID)
        {
//            var whereSql = @"WHERE AppInstanceID=@appInstanceID 
//                            AND ProcessGUID=@processGUID 
//                            AND ProcessInstanceID=@processInstanceID
//                        ORDER BY CreatedDateTime DESC";

            var transitionList = TransitionInstanceRepository.GetTransitionInstanceList(appInstanceID, processGUID, processInstanceID);

            return transitionList;
        }

        internal IList<WfActivityInstance> GetPreviousActivityInstance(WfActivityInstance runningNode,
            out bool hasGatewayNode)
        {
            hasGatewayNode = false;
            var transitionList = GetTransitionInstanceList(runningNode.AppInstanceID, 
                runningNode.ProcessGUID, 
                runningNode.AppInstanceID).ToList();

            var aim = new ActivityInstanceManager();
            var runningTransitionList = transitionList
                .Where(o => o.ToActivityInstanceID == runningNode.ID)
                .ToList();

            IList<WfActivityInstance> previousActivityInstanceList = new List<WfActivityInstance>();
            foreach (var entity in runningTransitionList)
            {
                //如果是逻辑节点，则继续查找
                if (entity.FromActivityType == (short)NodeTypeEnum.GatewayNode)
                {
                    GetPreviousOfGatewayActivityInstance(transitionList, entity.FromActivityInstanceID, previousActivityInstanceList);
                    hasGatewayNode = true;
                }
                else
                {
                    previousActivityInstanceList.Add(aim.GetById(entity.FromActivityInstanceID));
                }
            }
            return previousActivityInstanceList;
        }

        private void GetPreviousOfGatewayActivityInstance(IList<WfTransitionInstance> transitionList,
            long toActivityInstanceID,
            IList<WfActivityInstance> previousActivityInstanceList)
        {
            var previousTransitionList = transitionList
                .Where(o => o.ToActivityInstanceID == toActivityInstanceID)
                .ToList();

            var aim = new ActivityInstanceManager();
            foreach (var entity in previousTransitionList)
            {
                if (entity.FromActivityType == (short)NodeTypeEnum.TaskNode 
                    || entity.FromActivityType == (short)NodeTypeEnum.PluginNode
                    || entity.FromActivityType == (short)NodeTypeEnum.ScriptNode
                    || entity.FromActivityType == (short)NodeTypeEnum.StartNode)
                {
                    previousActivityInstanceList.Add(aim.GetById(entity.FromActivityInstanceID));
                }
                else if (entity.FromActivityType == (short)NodeTypeEnum.GatewayNode)
                {
                    GetPreviousOfGatewayActivityInstance(transitionList, entity.FromActivityInstanceID, previousActivityInstanceList);
                }
            }
        }

        internal void Insert(WfTransitionInstance entity )
        {
            TransitionInstanceRepository.Add(entity); 

            Debug.WriteLine(string.Format("transition instance inserted, time:{0}", System.DateTime.Now.ToString()));
        }



        /// <summary>
        /// 删除转移实例
        /// </summary>
        /// <param name="transitionInstanceID"></param>
        /// <param name="wfLinqDataContext"></param>
        internal void Delete(int transitionInstanceID)
        {
            TransitionInstanceRepository.Delete<WfTransitionInstance>(transitionInstanceID );
        }
        #endregion

        /// <summary>
        /// 判读定义的Transition是否已经被实例化执行
        /// </summary>
        internal bool IsTransiionInstancedAndConditionParsedOK(Guid transitionGUID,
            IList<WfTransitionInstance> transitionInstanceList)
        {
            bool isConainedAndCompletedOK = false;
            foreach (WfTransitionInstance transitionInstance in transitionInstanceList)
            {
                //判断连线是否被实例化，并且条件是否满足
                if (transitionGUID == transitionInstance.TransitionGUID)
                {
                    if (transitionInstance.ConditionParseResult == (byte)ConditionParseResultEnum.Passed)
                    {
                        isConainedAndCompletedOK = true;
                        break;
                    }
                }
            }
            return isConainedAndCompletedOK;
        }
    }
}
